package mmpathgen.controlflowanalysis;

import java.io.File;
import java.util.Iterator;
import java.util.List;

import soot.Body;
import soot.Scene;
import soot.SootClass;
import soot.SootMethod;
import soot.SourceLocator;
import soot.jimple.Stmt;
import soot.tagkit.LineNumberTag;
import soot.tagkit.Tag;
import soot.toolkits.graph.BriefUnitGraph;
import soot.toolkits.graph.ExceptionalUnitGraph;
import soot.toolkits.graph.TrapUnitGraph;
import soot.toolkits.graph.UnitGraph;
import soot.util.cfgcmd.CFGToDotGraph;
import soot.util.dot.DotGraph;

public class ControlFlowAnalysis {

	public final static int DANGLING = 0;
	public final static int HIERARCHY = 1;
	public final static int SIGNATURES = 2;
	public final static int BODIES = 3;
	
	
	public static void main(String[] args) {
		String packageName = "jtopas";
		String className = "ContentsExtractor";
		String methodName = "main";

		UnitGraph g = CFGGenByBriefUnitGraph.cfgGen(packageName + "."
				+ className, methodName);
		ControlFlowAnalysis.printCFGAsDot(g, packageName + "." + className,
				methodName);

	}
	
	public static void printCFGAsDot(UnitGraph g, String className,
			String methodName) {
		// System.out.println("[Control Flow Graph]");

		// Set up the class we're working with
		SootClass c = Scene.v().loadClassAndSupport(className);
		c.setApplicationClass();

		c.checkLevel(SIGNATURES);
		boolean found = false;
		SootMethod foundMethod = null;

		Iterator<SootMethod> methodIt = c.methodIterator();

		while (methodIt.hasNext()) {
			SootMethod method = methodIt.next();

			if (method.getName().equals(methodName)) {
				found = true;
				foundMethod = method;
				break;
			}
		}

		if (found) {
			// Retrieve the method and its body
			SootMethod m = foundMethod;
			Body b = m.retrieveActiveBody();

			// System.out.println("  |- will treat " + className + "." +
			// methodName);

			CFGToDotGraph cfg2dot = new CFGToDotGraph();

			DotGraph dot = cfg2dot.drawCFG(g, b);

			String cfaType;
			String cfgName;
			if (g instanceof BriefUnitGraph) {
				cfaType = "Brief";
				cfgName = "ControlFlowGraph_" + className + "." + methodName
						+ DotGraph.DOT_EXTENSION;
			} else if (g instanceof ExceptionalUnitGraph) {
				cfaType = "Exceptional";
				cfgName = "ControlFlowGraphByExceptionalUnitGraph_" + className
						+ "." + methodName + DotGraph.DOT_EXTENSION;
			} else if (g instanceof TrapUnitGraph) {
				cfaType = "Trap";
				cfgName = "ControlFlowGraphByTrapUnitGraph_" + className + "."
						+ methodName + DotGraph.DOT_EXTENSION;
			}
			else {
				System.err.println("Error: wrong UnitGraph type!");
				return;
			}

			File f = new File(SourceLocator.v().getOutputDir(), cfgName);
			dot.plot(f.getPath());

		} else {
			throw new RuntimeException("couldn't find method " + className
					+ "." + methodName);
		}
	}

	public static void printCFGAsDot(UnitGraph g, String className,
			String methodName, String mainClass, String cgaType, String filtType, String cfaType) {
		// System.out.println("[Control Flow Graph]");

		// Set up the class we're working with
		SootClass c = Scene.v().loadClassAndSupport(className);
		c.setApplicationClass();

		c.checkLevel(SIGNATURES);
		boolean found = false;
		SootMethod foundMethod = null;

		Iterator<SootMethod> methodIt = c.methodIterator();

		while (methodIt.hasNext()) {
			SootMethod method = methodIt.next();

			if (method.getName().equals(methodName)) {
				found = true;
				foundMethod = method;
				break;
			}
		}

		if (found) {
			// Retrieve the method and its body
			SootMethod m = foundMethod;
			Body b = m.retrieveActiveBody();

			// System.out.println("  |- will treat " + className + "." +
			// methodName);

			CFGToDotGraph cfg2dot = new CFGToDotGraph();

			DotGraph dot = cfg2dot.drawCFG(g, b);

			String cfgName;
			if (g instanceof BriefUnitGraph)
				cfgName = "ControlFlowGraph_" + className + "." + methodName
						+ DotGraph.DOT_EXTENSION;
			else if (g instanceof ExceptionalUnitGraph)
				cfgName = "ControlFlowGraphByExceptionalUnitGraph_" + className
						+ "." + methodName + DotGraph.DOT_EXTENSION;
			else if (g instanceof TrapUnitGraph)
				cfgName = "ControlFlowGraphByTrapUnitGraph_" + className + "."
						+ methodName + DotGraph.DOT_EXTENSION;
			else {
				System.err.println("Error: wrong UnitGraph type!");
				return;
			}

			File f = new File(SourceLocator.v().getOutputDir(), cfgName);
			dot.plot(f.getPath());

		} else {
			throw new RuntimeException("couldn't find method " + className
					+ "." + methodName);
		}
	}

	public static int getLineNumber(Stmt s) {
		List<Tag> tags = s.getTags();
		for (Tag t : tags) {
			if (t instanceof LineNumberTag)
				return Integer.parseInt(t.toString());
		}
		return -1;
	}
}
